package domain;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import exception.IllegalPeriodException;
import exception.IllegalPrerequisiteException;

public class Discipline implements Teachable {
	
	private final String AUTO_PREREQUISITE = "Invalid Prerequisite. Auto Prerequisite is not acceptable.";
	private final String INVALID_PREREQUISITE_PERIOD = "Invalid Prerequsite. Prerequisite period must be between 1 and period of this discipline - 1.";
	private final String INVALID_PERIOD = "Invalid Period. Mininum period is 1.";
	
	private String name;
	private String code;
	private int period;
	private List<Discipline> prerequisites;
	private List<Class> classes;
	private PTime totalDurationForEachPresentable;
	
	private HashMap<Integer, ArrayList<Discipline>> blockedDisciplines;
	
	public Discipline(String name, int period, PTime duration) throws IllegalPeriodException, IllegalPrerequisiteException {
		this.setName(name);
		this.setPeriod(period);
		this.setTotalDurationForEachPresentable(duration);
		this.setPrerequisites(new ArrayList<Discipline>());
		this.setPresentables(new ArrayList<Class>());
		
		this.blockedDisciplines = new HashMap<Integer, ArrayList<Discipline>>();
	
	}

	public Discipline(String string, int int1, String string2) {
		// TODO Auto-generated constructor stub
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public int getPeriod() {
		return period;
	}

	public void setPeriod(int period) throws IllegalPeriodException {
		if (period < 1) {
			throw new IllegalPeriodException(INVALID_PERIOD);
		}
		this.period = period;
	}

	public List<Discipline> getPrerequisites() {
		return this.prerequisites;
	}
	
	public void setPrerequisites(List<Discipline> prerequisites) throws IllegalPrerequisiteException {
		for (Discipline prerequisite : prerequisites) {
			this.addPrerequisite(prerequisite);
		}
	}
	
	public void addPrerequisite(Discipline prerequisite) throws IllegalPrerequisiteException {
		if (this.getPrerequisites().contains(prerequisite)) {
			throw new IllegalPrerequisiteException(AUTO_PREREQUISITE);
		}
		if (prerequisite.getPeriod() >= this.getPeriod()) {
			throw new IllegalPrerequisiteException(INVALID_PREREQUISITE_PERIOD);
		}
		this.prerequisites.add(prerequisite);
	}

	@Override
	public List<Class> getPresentables() {
		return classes;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void setPresentables(List<? extends Presentable> p) {
		this.classes = (List<Class>) p;
	}
	
	@Override
	public void addPresentable(Presentable p) {
		this.classes.add((Class) p);
	}

	@Override
	public List<Professor> getAccountables() {
		List<Professor> professors = new ArrayList<Professor>();
		for (Class c : classes) {
			Professor t = c.getAccountable();
			if (!professors.contains(t)) {
				professors.add(t);
			}
		}
		return professors;
	}

	@Override
	public List<Class> getPresentablesByAccountable(Accountable a) {
		List<Class> classesOfAccountable = new ArrayList<Class>();
		for (Class c : this.getPresentables()) {
			if (c.getAccountable().equals(a)) {
				classesOfAccountable.add(c);
			}
		}
		return classesOfAccountable;
	}

	@Override
	public void removePresentable(Presentable p) {
		this.classes.remove(p);
	}

	@Override
	public PTime getTotalDurationForEachPresentable() {
		return this.totalDurationForEachPresentable;
	}

	@Override
	public void setTotalDurationForEachPresentable(PTime p) {
		this.totalDurationForEachPresentable = p;
	}
	
	public ArrayList<Discipline> getBlockedDisciplines(Integer priorityLevel) {
		return blockedDisciplines.get(priorityLevel);
	}
	
	public void addBlockedDiscipline(Integer priorityLevel, Discipline discipline){
		if (blockedDisciplines.containsKey(priorityLevel)) blockedDisciplines.get(priorityLevel).add(discipline);
		else{
			ArrayList<Discipline> newDisciplines = new ArrayList<Discipline>();
			newDisciplines.add(discipline);
			blockedDisciplines.put(priorityLevel, newDisciplines);
		}
	}

	public boolean validateDiscipline(Discipline discipline) {
		if (blockedDisciplines.containsValue(discipline))
			return false;

		return true;
	}

}
